package wechatpay

import (
	"context"
	"errors"
	"github.com/goravel/framework/support/path"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
)

// MerchantConfig 商户配置信息
type MerchantConfig struct {
	MchID                string
	MchCertificateSerial string
	MchAPIv3Key          string
	AppID                string
	NotifyURL            string
}

// WechatpayService 封装微信支付服务的结构体
type WechatpayService struct {
	client *core.Client
	config *MerchantConfig
}
type PrepayWithRequestPaymentResponse struct {
	// 预支付交易会话标识
	PrepayId *string `json:"prepay_id"` // revive:disable-line:var-naming
	// 应用ID
	Appid *string `json:"appId"`
	// 时间戳
	TimeStamp *string `json:"timeStamp"`
	// 随机字符串
	NonceStr *string `json:"nonceStr"`
	// 订单详情扩展字符串
	Package *string `json:"package"`
	// 签名方式
	SignType *string `json:"signType"`
	// 签名
	PaySign *string `json:"paySign"`
}

// NewWechatpayService 创建一个新的微信支付服务实例
func NewWechatpayService(config *MerchantConfig) (*WechatpayService, error) {
	// 加载商户私钥
	mchPrivateKey, err1 := utils.LoadPrivateKeyWithPath(path.App("/keys/apiclient_key.pem"))
	if err1 != nil {
		return nil, err1
	}
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(
			config.MchID,
			config.MchCertificateSerial,
			mchPrivateKey,
			config.MchAPIv3Key,
		),
	}

	ctx := context.Background()
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		return nil, errors.New(err.Error())
	}
	return &WechatpayService{
		client: client,
		config: config,
	}, nil
}

// PrepareJSAPITransaction 准备JSAPI交易并获取预支付ID
func (s *WechatpayService) PrepareJSAPITransaction(ctx context.Context, description string, outTradeNo string, totalFee int64, openid string) (*PrepayWithRequestPaymentResponse, error) {
	prepayRequest := jsapi.PrepayRequest{
		Appid:       core.String(s.config.AppID),
		Mchid:       core.String(s.config.MchID),
		Description: core.String(description),
		OutTradeNo:  core.String(outTradeNo),
		Amount: &jsapi.Amount{
			Total: core.Int64(totalFee),
		},
		Payer: &jsapi.Payer{
			Openid: core.String(openid),
		},
		NotifyUrl: core.String(s.config.NotifyURL),
	}
	// 调用预支付接口
	svc := jsapi.JsapiApiService{Client: s.client}
	prepayResp, _, err := svc.PrepayWithRequestPayment(ctx, prepayRequest)
	if err != nil {
		return nil, err
	}
	var response PrepayWithRequestPaymentResponse
	response.Appid = prepayResp.Appid
	response.TimeStamp = prepayResp.TimeStamp
	response.TimeStamp = prepayResp.TimeStamp
	response.NonceStr = prepayResp.NonceStr
	response.Package = prepayResp.Package
	response.SignType = prepayResp.SignType
	response.PaySign = prepayResp.PaySign

	return &response, nil
}
